package case25

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/validator/v10"
	"net/http"
	"regexp"
)

func Test() {
	fmt.Println("🎯示例二十五：自定义验证器-使用结构体校验")

	r := gin.Default()

	// 设置校验器
	setupValidator()

	// Login
	r.POST("/login", func(c *gin.Context) {

		var param LoginParam
		if err := c.ShouldBindJSON(&param); err != nil {
			// 处理验证错误
			if validationErrors, ok := err.(validator.ValidationErrors); ok {
				for _, fieldError := range validationErrors {
					switch fieldError.Tag() {
					case "username":
						c.JSON(http.StatusBadRequest, gin.H{
							"error": "用户名不能为空",
						})
						c.Abort()
						return
					case "password":
						c.JSON(http.StatusBadRequest, gin.H{
							"error": "密码必须8-32位，且包含字母和数字",
						})
						c.Abort()
						return
					case "required":
						c.JSON(http.StatusBadRequest, gin.H{
							"error": fieldError.Field() + "是必填字段",
						})
						c.Abort()
						return
					default:
						c.JSON(http.StatusBadRequest, gin.H{
							"error": fieldError.Error(),
						})

					}
				}
				return
			}
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		c.JSON(200, gin.H{
			"username": param.Username,
			"password": param.Password,
		})
	})

	r.Run(":60000")

}

// 定义结构体
type LoginParam struct {
	Username string `json:"username" binding:"required,username"`
	Password string `json:"password" binding:"required,password,min=6"`
}

// username 验证器
func validUsername(fl validator.FieldLevel) bool {
	username := fl.Field().String()
	if username == "" || len(username) == 0 {
		return false
	}

	return true
}

// password 验证器
func validPassword(fl validator.FieldLevel) bool {
	password := fl.Field().String()

	if len(password) < 6 {
		return false
	}

	// 修复后的正则：必须同时包含数字和字母，并且匹配整个字符串
	hasDigit := regexp.MustCompile(`[0-9]`).MatchString(password)
	hasLetter := regexp.MustCompile(`[a-zA-Z]`).MatchString(password)

	if !hasDigit || !hasLetter {
		return false
	}
	return true
}

// 注册自定义校验器
func setupValidator() {
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		// 注册结构体字段校验器
		v.RegisterValidation("username", validUsername)
		v.RegisterValidation("password", validPassword)

		// 注册结构体验证
		v.RegisterStructValidation(useStructValid, LoginParam{})
	}
}

// 结构体级别的校验器
func useStructValid(sl validator.StructLevel) {
	user := sl.Current().Interface().(LoginParam)

	// 示例：用户名不能和密码相同
	if user.Username == user.Password {
		sl.ReportError(user.Username, "Password", "Password", "username_password_diff", "")
	}

}
